// package com.mapresso;

/**
 * ***************************************************************************************
 * Transformer
 * 
 * @author Adrian Herzog
 * @version 1.0
 */

import java.awt.Point;
import java.awt.Rectangle;

class Transformer extends Object {

	private FRectangle world;
	public FRectangle worldFixed;
	public boolean fixedBox;
	private Rectangle screen;
	private double factor;
	private double initialFactor;
	private boolean valid;
	public boolean redefined;

	public Transformer(FRectangle world0, Rectangle screen0) {
		this();
		init(world0, screen0);
		// Log.trace("Transformer");
	}

	Transformer() {
		redefined = true;
		valid = false;
		// Log.trace("Transformer()");
	}

	void init(FRectangle world0, Rectangle screen0) {
		world = world0;
		screen = screen0;
		calcFactor();
		// Log.trace("init");
		return;
	}

	void setScreenRect(Rectangle screen0) {
		screen = screen0;
		valid = false;
		// Log.trace("setScreenRect");
		return;
	}

	void setFixed(FRectangle fixedBox0) {
		worldFixed = fixedBox0;
		// Log.trace("setFixed1");
		setWorld(worldFixed);
		fixedBox = true;
		// Log.trace("setFixed2");
	}

	void resetFixed() {
		// Log.trace("resetFixed1");
		setWorld(worldFixed);
		// Log.trace("resetFixed2");
	}

	void setWorld(FRectangle world0) {
		world = world0;
		if (fixedBox) {
			// Log.trace("setWorld " + world);
			// Log.trace("Globals.worldFixed " + worldFixed);
			world.notOutside(worldFixed);
		}
		valid = false;
		// Log.trace("setWorld " + world);
		return;
	}

	void move(int dx, int dy) {
		if (!valid)
			calcFactor();
		screen.x += dx;
		screen.y += dy;
		return;
	}

	boolean worldOK() {
// // Log.trace("boxOK " + world);
		return world != null;
	}

	void zoomOut(double factor, FPoint p) {
		// Log.trace("zoomOut");
		setWorld(world.zoomOut(factor, p));
	}

	void pan(FPoint p1, FPoint p2) {
		// Log.trace("pan");
		setWorld(world.pan(p1, p2));
	}

	int transformx(float x) {
		if (!valid)
			calcFactor();
		return screen.x + (int) Math.round(factor * (x - world.xmin));
	}

	int transformy(float y) {
		if (!valid)
			calcFactor();
		return screen.y + (int) Math.round(factor * (world.ymax - y));
	}

	Point transform(FPoint w) {
		if (!valid)
			calcFactor();
		return new Point(screen.x
				+ (int) Math.round(factor * (w.x - world.xmin)), screen.y
				+ (int) Math.round(factor * (world.ymax - w.y)));
	}

	Rectangle transform(FRectangle p) {
		if (!valid)
			calcFactor();
		return new Rectangle(transformx(p.xmin), transformy(p.ymax),
				1 + (int) Math.round(factor * (p.xmax - p.xmin)),
				1 + (int) Math.round(factor * (p.ymax - p.ymin)));
	}

	FPoint transformback(Point w) {
		if (!valid)
			calcFactor();
		return new FPoint((float) ((w.x - screen.x) / factor + world.xmin),
				(float) (world.ymax - (w.y - screen.y) / factor));
	}

	double transformback(int dist) {
		if (!valid)
			calcFactor();
		return dist / factor;
	}

	FPoint transformback(int x, int y) {
		if (!valid)
			calcFactor();
		return new FPoint((float) ((x - screen.x) / factor + world.xmin),
				(float) (world.ymax - (y - screen.y) / factor));
	}

	int transform(float f) {
		if (!valid)
			calcFactor();
		return (int) Math.round(factor * f);
	}

	double getFactor() {
		if (!valid)
			calcFactor();
		return factor;
	}

	double getInitialZoomFactor() {
		return initialFactor;
	}

	double getZoomFactor() {
		if (!valid)
			calcFactor();
		return factor;
	}

	public String toString() {
		return "f: " + factor + " / " + getZoomFactor() + "\n  Screen: "
				+ screen + "\n  World: " + world;
	}

	private void calcFactor() {
		// Log.trace("calcFactor: screen " + screen + " || world " + world);
		factor = Math.min((double) screen.width / (world.xmax - world.xmin),
				(double) screen.height / (world.ymax - world.ymin));
		if (initialFactor == 0.0)
			initialFactor = factor;
		valid = true;
		redefined = true;
	}

	public void setDefined() {
		redefined = false;
	}

	public boolean getRedefined() {
		return redefined;
	}
}
